home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / nose / loader.py < prev    next >
Text File  |  2009-05-13  |  23KB  |  563 lines

  1. """
  2. Test Loader
  3. -----------
  4.  
  5. nose's test loader implements the same basic functionality as its
  6. superclass, unittest.TestLoader, but extends it by more liberal
  7. interpretations of what may be a test and how a test may be named.
  8. """
  9. from __future__ import generators
  10.  
  11. import logging
  12. import os
  13. import sys
  14. import unittest
  15. from inspect import isfunction, ismethod
  16. from nose.case import FunctionTestCase, MethodTestCase
  17. from nose.failure import Failure
  18. from nose.config import Config
  19. from nose.importer import Importer, add_path, remove_path
  20. from nose.selector import defaultSelector, TestAddress
  21. from nose.util import cmp_lineno, getpackage, isclass, isgenerator, ispackage, \
  22.     match_last, resolve_name, transplant_func, transplant_class, test_address
  23. from nose.suite import ContextSuiteFactory, ContextList, LazySuite
  24.  
  25.  
  26. log = logging.getLogger(__name__)
  27. #log.setLevel(logging.DEBUG)
  28.  
  29. # for efficiency and easier mocking
  30. op_normpath = os.path.normpath
  31. op_abspath = os.path.abspath
  32. op_join = os.path.join
  33. op_isdir = os.path.isdir
  34. op_isfile = os.path.isfile
  35.  
  36.  
  37. __all__ = ['TestLoader', 'defaultTestLoader']
  38.  
  39.  
  40. class TestLoader(unittest.TestLoader):
  41.     """Test loader that extends unittest.TestLoader to:
  42.  
  43.     * Load tests from test-like functions and classes that are not
  44.       unittest.TestCase subclasses
  45.     * Find and load test modules in a directory
  46.     * Support tests that are generators
  47.     * Support easy extensions of or changes to that behavior through plugins
  48.     """
  49.     config = None
  50.     importer = None
  51.     workingDir = None
  52.     selector = None
  53.     suiteClass = None
  54.     
  55.     def __init__(self, config=None, importer=None, workingDir=None,
  56.                  selector=None):
  57.         """Initialize a test loader.
  58.  
  59.         Parameters (all optional):
  60.  
  61.         * config: provide a `nose.config.Config`_ or other config class
  62.           instance; if not provided a `nose.config.Config`_ with
  63.           default values is used.          
  64.         * importer: provide an importer instance that implements
  65.           `importFromPath`. If not provided, a
  66.           `nose.importer.Importer`_ is used.
  67.         * workingDir: the directory to which file and module names are
  68.           relative. If not provided, assumed to be the current working
  69.           directory.
  70.         * selector: a selector class or instance. If a class is
  71.           provided, it will be instantiated with one argument, the
  72.           current config. If not provided, a `nose.selector.Selector`_
  73.           is used.
  74.         """
  75.         if config is None:
  76.             config = Config()
  77.         if importer is None:
  78.             importer = Importer(config=config)
  79.         if workingDir is None:
  80.             workingDir = config.workingDir
  81.         if selector is None:
  82.             selector = defaultSelector(config)
  83.         elif isclass(selector):
  84.             selector = selector(config)
  85.         self.config = config
  86.         self.importer = importer
  87.         self.workingDir = op_normpath(op_abspath(workingDir))
  88.         self.selector = selector
  89.         if config.addPaths:
  90.             add_path(workingDir, config)        
  91.         self.suiteClass = ContextSuiteFactory(config=config)
  92.         unittest.TestLoader.__init__(self)     
  93.  
  94.     def getTestCaseNames(self, testCaseClass):
  95.         """Override to select with selector, unless
  96.         config.getTestCaseNamesCompat is True
  97.         """
  98.         if self.config.getTestCaseNamesCompat:
  99.             return unittest.TestLoader.getTestCaseNames(self, testCaseClass)
  100.         
  101.         def wanted(attr, cls=testCaseClass, sel=self.selector):
  102.             item = getattr(cls, attr, None)
  103.             if not ismethod(item):
  104.                 return False
  105.             return sel.wantMethod(item)
  106.         cases = filter(wanted, dir(testCaseClass))
  107.         for base in testCaseClass.__bases__:
  108.             for case in self.getTestCaseNames(base):
  109.                 if case not in cases:
  110.                     cases.append(case)
  111.         # add runTest if nothing else picked
  112.         if not cases and hasattr(testCaseClass, 'runTest'):
  113.             cases = ['runTest']
  114.         if self.sortTestMethodsUsing:
  115.             cases.sort(self.sortTestMethodsUsing)
  116.         return cases
  117.  
  118.     def loadTestsFromDir(self, path):
  119.         """Load tests from the directory at path. This is a generator
  120.         -- each suite of tests from a module or other file is yielded
  121.         and is expected to be executed before the next file is
  122.         examined.
  123.         """        
  124.         log.debug("load from dir %s", path)
  125.         plugins = self.config.plugins
  126.         plugins.beforeDirectory(path)
  127.         if self.config.addPaths:
  128.             paths_added = add_path(path, self.config)
  129.  
  130.         entries = os.listdir(path)
  131.         entries.sort(lambda a, b: match_last(a, b, self.config.testMatch))
  132.         for entry in entries:
  133.             # this hard-coded initial-dot test will be removed:
  134.             # http://code.google.com/p/python-nose/issues/detail?id=82
  135.             if entry.startswith('.'):
  136.                 continue
  137.             entry_path = op_abspath(op_join(path, entry))
  138.             is_file = op_isfile(entry_path)
  139.             wanted = False
  140.             if is_file:
  141.                 is_dir = False
  142.                 wanted = self.selector.wantFile(entry_path)
  143.             else:
  144.                 is_dir = op_isdir(entry_path)
  145.                 if is_dir:
  146.                     # this hard-coded initial-underscore test will be removed:
  147.                     # http://code.google.com/p/python-nose/issues/detail?id=82
  148.                     if entry.startswith('_'):
  149.                         continue
  150.                     wanted = self.selector.wantDirectory(entry_path)
  151.             is_package = ispackage(entry_path)
  152.             if wanted:
  153.                 if is_file:
  154.                     plugins.beforeContext()
  155.                     if entry.endswith('.py'):
  156.                         yield self.loadTestsFromName(
  157.                             entry_path, discovered=True)
  158.                     else:
  159.                         yield self.loadTestsFromFile(entry_path)
  160.                     plugins.afterContext()
  161.                 elif is_package:
  162.                     # Load the entry as a package: given the full path,
  163.                     # loadTestsFromName() will figure it out
  164.                     yield self.loadTestsFromName(
  165.                         entry_path, discovered=True)
  166.                 else:
  167.                     # Another test dir in this one: recurse lazily
  168.                     yield self.suiteClass(
  169.                         lambda: self.loadTestsFromDir(entry_path))
  170.         tests = []
  171.         for test in plugins.loadTestsFromDir(path):
  172.             tests.append(test)
  173.         # TODO: is this try/except needed?
  174.         try:
  175.             if tests:
  176.                 yield self.suiteClass(tests)
  177.         except (KeyboardInterrupt, SystemExit):
  178.             raise
  179.         except:
  180.             yield self.suiteClass([Failure(*sys.exc_info())])
  181.         
  182.         # pop paths
  183.         if self.config.addPaths:
  184.             map(remove_path, paths_added)
  185.         plugins.afterDirectory(path)
  186.  
  187.     def loadTestsFromFile(self, filename):
  188.         """Load tests from a non-module file. Default is to raise a
  189.         ValueError; plugins may implement `loadTestsFromFile` to
  190.         provide a list of tests loaded from the file.
  191.         """
  192.         log.debug("Load from non-module file %s", filename)
  193.         try:
  194.             tests = [test for test in
  195.                      self.config.plugins.loadTestsFromFile(filename)]
  196.             if tests:
  197.                 # Plugins can yield False to indicate that they were
  198.                 # unable to load tests from a file, but it was not an
  199.                 # error -- the file just had no tests to load.
  200.                 tests = filter(None, tests)
  201.                 return self.suiteClass(tests)
  202.             else:
  203.                 # Nothing was able to even try to load from this file
  204.                 open(filename, 'r').close() # trigger os error
  205.                 raise ValueError("Unable to load tests from file %s"
  206.                                  % filename)
  207.         except (KeyboardInterrupt, SystemExit):
  208.             raise
  209.         except:
  210.             exc = sys.exc_info()
  211.             return self.suiteClass(
  212.                 [Failure(exc[0], exc[1], exc[2],
  213.                          address=(filename, None, None))])
  214.  
  215.     def loadTestsFromGenerator(self, generator, module):
  216.         """Lazy-load tests from a generator function. The generator function
  217.         may yield either:
  218.  
  219.         * a callable, or
  220.         * a function name resolvable within the same module
  221.         """
  222.         def generate(g=generator, m=module):
  223.             try:
  224.                 for test in g():
  225.                     test_func, arg = self.parseGeneratedTest(test)
  226.                     if not callable(test_func):
  227.                         test_func = getattr(m, test_func)
  228.                     yield FunctionTestCase(test_func, arg=arg, descriptor=g)
  229.             except KeyboardInterrupt:
  230.                 raise
  231.             except:
  232.                 exc = sys.exc_info()
  233.                 yield Failure(exc[0], exc[1], exc[2],
  234.                               address=test_address(generator))
  235.         return self.suiteClass(generate, context=generator, can_split=False)
  236.  
  237.     def loadTestsFromGeneratorMethod(self, generator, cls):
  238.         """Lazy-load tests from a generator method.
  239.  
  240.         This is more complicated than loading from a generator function,
  241.         since a generator method may yield:
  242.  
  243.         * a function
  244.         * a bound or unbound method, or
  245.         * a method name
  246.         """
  247.         # convert the unbound generator method
  248.         # into a bound method so it can be called below
  249.         cls = generator.im_class
  250.         inst = cls()
  251.         method = generator.__name__
  252.         generator = getattr(inst, method)
  253.  
  254.         def generate(g=generator, c=cls):
  255.             try:
  256.                 for test in g():
  257.                     test_func, arg = self.parseGeneratedTest(test)
  258.                     if not callable(test_func):
  259.                         test_func = getattr(c, test_func)
  260.                     if ismethod(test_func):
  261.                         yield MethodTestCase(test_func, arg=arg, descriptor=g)
  262.                     elif isfunction(test_func):
  263.                         # In this case we're forcing the 'MethodTestCase'
  264.                         # to run the inline function as its test call,
  265.                         # but using the generator method as the 'method of
  266.                         # record' (so no need to pass it as the descriptor)
  267.                         yield MethodTestCase(g, test=test_func, arg=arg)
  268.                     else:
  269.                         yield Failure(
  270.                             TypeError,
  271.                             "%s is not a function or method" % test_func)
  272.             except KeyboardInterrupt:
  273.                 raise
  274.             except:
  275.                 exc = sys.exc_info()
  276.                 yield Failure(exc[0], exc[1], exc[2],
  277.                               address=test_address(generator))
  278.         return self.suiteClass(generate, context=generator, can_split=False)
  279.  
  280.     def loadTestsFromModule(self, module, path=None, discovered=False):
  281.         """Load all tests from module and return a suite containing
  282.         them. If the module has been discovered and is not test-like,
  283.         the suite will be empty by default, though plugins may add
  284.         their own tests.
  285.         """
  286.         log.debug("Load from module %s", module)
  287.         tests = []
  288.         test_classes = []
  289.         test_funcs = []
  290.         # For *discovered* modules, we only load tests when the module looks
  291.         # testlike. For modules we've been directed to load, we always
  292.         # look for tests. (discovered is set to True by loadTestsFromDir)
  293.         if not discovered or self.selector.wantModule(module):
  294.             for item in dir(module):
  295.                 test = getattr(module, item, None)
  296.                 # print "Check %s (%s) in %s" % (item, test, module.__name__)
  297.                 if isclass(test):
  298.                     if self.selector.wantClass(test):
  299.                         test_classes.append(test)
  300.                 elif isfunction(test) and self.selector.wantFunction(test):
  301.                     test_funcs.append(test)
  302.             test_classes.sort(lambda a, b: cmp(a.__name__, b.__name__))
  303.             test_funcs.sort(cmp_lineno)
  304.             tests = map(lambda t: self.makeTest(t, parent=module),
  305.                         test_classes + test_funcs)
  306.  
  307.         # Now, descend into packages
  308.         # FIXME can or should this be lazy?
  309.         # is this syntax 2.2 compatible?
  310.         module_paths = getattr(module, '__path__', [])
  311.         if path:
  312.             path = os.path.realpath(path)
  313.         for module_path in module_paths:
  314.             if (self.config.traverseNamespace or not path) or \
  315.                     os.path.realpath(module_path).startswith(path):
  316.                 tests.extend(self.loadTestsFromDir(module_path))
  317.             
  318.         for test in self.config.plugins.loadTestsFromModule(module, path):
  319.             tests.append(test)
  320.  
  321.         return self.suiteClass(ContextList(tests, context=module))
  322.     
  323.     def loadTestsFromName(self, name, module=None, discovered=False):
  324.         """Load tests from the entity with the given name.
  325.  
  326.         The name may indicate a file, directory, module, or any object
  327.         within a module. See `nose.util.split_test_name` for details on
  328.         test name parsing.
  329.         """
  330.         # FIXME refactor this method into little bites?
  331.         log.debug("load from %s (%s)", name, module)
  332.         
  333.         suite = self.suiteClass
  334.  
  335.         # give plugins first crack
  336.         plug_tests = self.config.plugins.loadTestsFromName(name, module)
  337.         if plug_tests:
  338.             return suite(plug_tests)
  339.         
  340.         addr = TestAddress(name, workingDir=self.workingDir)
  341.         if module:
  342.             # Two cases:
  343.             #  name is class.foo
  344.             #    The addr will be incorrect, since it thinks class.foo is
  345.             #    a dotted module name. It's actually a dotted attribute
  346.             #    name. In this case we want to use the full submitted
  347.             #    name as the name to load from the module.
  348.             #  name is module:class.foo
  349.             #    The addr will be correct. The part we want is the part after
  350.             #    the :, which is in addr.call.
  351.             if addr.call:
  352.                 name = addr.call
  353.             parent, obj = self.resolve(name, module)
  354.             if (isclass(parent)
  355.                 and getattr(parent, '__module__', None) != module.__name__):
  356.                 parent = transplant_class(parent, module.__name__)
  357.                 obj = getattr(parent, obj.__name__)
  358.             log.debug("parent %s obj %s module %s", parent, obj, module)
  359.             if isinstance(obj, Failure):
  360.                 return suite([obj])
  361.             else:
  362.                 return suite(ContextList([self.makeTest(obj, parent)],
  363.                                          context=parent))
  364.         else:
  365.             if addr.module:
  366.                 try:
  367.                     if addr.filename is None:
  368.                         module = resolve_name(addr.module)
  369.                     else:
  370.                         self.config.plugins.beforeImport(
  371.                             addr.filename, addr.module)
  372.                         # FIXME: to support module.name names,
  373.                         # do what resolve-name does and keep trying to
  374.                         # import, popping tail of module into addr.call,
  375.                         # until we either get an import or run out of
  376.                         # module parts
  377.                         try:
  378.                             module = self.importer.importFromPath(
  379.                                 addr.filename, addr.module)
  380.                         finally:
  381.                             self.config.plugins.afterImport(
  382.                                 addr.filename, addr.module)
  383.                 except (KeyboardInterrupt, SystemExit):
  384.                     raise
  385.                 except:
  386.                     exc = sys.exc_info()
  387.                     return suite([Failure(exc[0], exc[1], exc[2],
  388.                                           address=addr.totuple())])
  389.                 if addr.call:
  390.                     return self.loadTestsFromName(addr.call, module)
  391.                 else:
  392.                     return self.loadTestsFromModule(
  393.                         module, addr.filename,
  394.                         discovered=discovered)
  395.             elif addr.filename:
  396.                 path = addr.filename
  397.                 if addr.call:
  398.                     package = getpackage(path)
  399.                     if package is None:
  400.                         return suite([
  401.                             Failure(ValueError,
  402.                                     "Can't find callable %s in file %s: "
  403.                                     "file is not a python module" %
  404.                                     (addr.call, path),
  405.                                     address=addr.totuple())])
  406.                     return self.loadTestsFromName(addr.call, module=package)
  407.                 else:
  408.                     if op_isdir(path):
  409.                         # In this case we *can* be lazy since we know
  410.                         # that each module in the dir will be fully
  411.                         # loaded before its tests are executed; we
  412.                         # also know that we're not going to be asked
  413.                         # to load from . and ./some_module.py *as part
  414.                         # of this named test load*
  415.                         return LazySuite(
  416.                             lambda: self.loadTestsFromDir(path))
  417.                     elif op_isfile(path):
  418.                         return self.loadTestsFromFile(path)
  419.                     else:
  420.                         return suite([
  421.                                 Failure(OSError, "No such file %s" % path,
  422.                                         address=addr.totuple())])
  423.             else:
  424.                 # just a function? what to do? I think it can only be
  425.                 # handled when module is not None
  426.                 return suite([
  427.                     Failure(ValueError, "Unresolvable test name %s" % name,
  428.                             address=addr.totuple())])
  429.  
  430.     def loadTestsFromNames(self, names, module=None):
  431.         """Load tests from all names, returning a suite containing all
  432.         tests.
  433.         """
  434.         plug_res = self.config.plugins.loadTestsFromNames(names, module)
  435.         if plug_res:
  436.             suite, names = plug_res
  437.             if suite:
  438.                 return self.suiteClass([
  439.                     self.suiteClass(suite),
  440.                     unittest.TestLoader.loadTestsFromNames(self, names, module)
  441.                     ])
  442.         return unittest.TestLoader.loadTestsFromNames(self, names, module)
  443.  
  444.     def loadTestsFromTestCase(self, testCaseClass):
  445.         """Load tests from a unittest.TestCase subclass.
  446.         """
  447.         cases = []
  448.         plugins = self.config.plugins
  449.         for case in plugins.loadTestsFromTestCase(testCaseClass):
  450.             cases.append(case)
  451.         # For efficiency in the most common case, just call and return from
  452.         # super. This avoids having to extract cases and rebuild a context
  453.         # suite when there are no plugin-contributed cases.
  454.         if not cases:
  455.             return super(TestLoader, self).loadTestsFromTestCase(testCaseClass)
  456.         cases.extend(
  457.             [case for case in
  458.              super(TestLoader, self).loadTestsFromTestCase(testCaseClass)])
  459.         return self.suiteClass(cases)
  460.     
  461.     def loadTestsFromTestClass(self, cls):
  462.         """Load tests from a test class that is *not* a unittest.TestCase
  463.         subclass.
  464.  
  465.         In this case, we can't depend on the class's `__init__` taking method
  466.         name arguments, so we have to compose a MethodTestCase for each
  467.         method in the class that looks testlike.
  468.         """
  469.         def wanted(attr, cls=cls, sel=self.selector):
  470.             item = getattr(cls, attr, None)
  471.             if not ismethod(item):
  472.                 return False
  473.             return sel.wantMethod(item)
  474.         cases = [self.makeTest(getattr(cls, case), cls)
  475.                  for case in filter(wanted, dir(cls))]
  476.         for test in self.config.plugins.loadTestsFromTestClass(cls):
  477.             cases.append(test)
  478.         return self.suiteClass(ContextList(cases, context=cls))
  479.  
  480.     def makeTest(self, obj, parent=None):
  481.         """Given a test object and its parent, return a test case
  482.         or test suite.
  483.         """
  484.         plug_tests = []
  485.         try:
  486.             addr = test_address(obj)
  487.         except KeyboardInterrupt:
  488.             raise
  489.         except:
  490.             addr = None
  491.         for test in self.config.plugins.makeTest(obj, parent):
  492.             plug_tests.append(test)
  493.         # TODO: is this try/except needed?
  494.         try:
  495.             if plug_tests:
  496.                 return self.suiteClass(plug_tests)
  497.         except (KeyboardInterrupt, SystemExit):
  498.             raise
  499.         except:
  500.             exc = sys.exc_info()
  501.             return Failure(exc[0], exc[1], exc[2], address=addr)
  502.         
  503.         if isinstance(obj, unittest.TestCase):
  504.             return obj
  505.         elif isclass(obj):
  506.             if parent and obj.__module__ != parent.__name__:
  507.                 obj = transplant_class(obj, parent.__name__)
  508.             if issubclass(obj, unittest.TestCase):
  509.                 return self.loadTestsFromTestCase(obj)
  510.             else:
  511.                 return self.loadTestsFromTestClass(obj)
  512.         elif ismethod(obj):
  513.             if parent is None:
  514.                 parent = obj.__class__
  515.             if issubclass(parent, unittest.TestCase):
  516.                 return parent(obj.__name__)
  517.             else:
  518.                 if isgenerator(obj):
  519.                     return self.loadTestsFromGeneratorMethod(obj, parent)
  520.                 else:
  521.                     return MethodTestCase(obj)
  522.         elif isfunction(obj):
  523.             if parent and obj.__module__ != parent.__name__:
  524.                 obj = transplant_func(obj, parent.__name__)
  525.             if isgenerator(obj):
  526.                 return self.loadTestsFromGenerator(obj, parent)
  527.             else:
  528.                 return FunctionTestCase(obj)
  529.         else:
  530.             return Failure(TypeError,
  531.                            "Can't make a test from %s" % obj,
  532.                            address=addr)
  533.  
  534.     def resolve(self, name, module):
  535.         """Resolve name within module
  536.         """
  537.         obj = module
  538.         parts = name.split('.')
  539.         for part in parts:
  540.             parent, obj = obj, getattr(obj, part, None)
  541.         if obj is None:
  542.             # no such test
  543.             obj = Failure(ValueError, "No such test %s" % name)
  544.         return parent, obj
  545.  
  546.     def parseGeneratedTest(self, test):
  547.         """Given the yield value of a test generator, return a func and args.
  548.  
  549.         This is used in the two loadTestsFromGenerator* methods.
  550.  
  551.         """
  552.         if not isinstance(test, tuple):         # yield test
  553.             test_func, arg = (test, tuple())
  554.         elif len(test) == 1:                    # yield (test,)
  555.             test_func, arg = (test[0], tuple())
  556.         else:                                   # yield test, foo, bar, ...
  557.             assert len(test) > 1 # sanity check
  558.             test_func, arg = (test[0], test[1:])
  559.         return test_func, arg
  560.  
  561. defaultTestLoader = TestLoader
  562.  
  563.